﻿using Core.Entities;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Core.Tools
{
    public static class StringHelper
    {
        /// <summary>
        /// 存储 MD5Cng 实例
        /// </summary>
        [ThreadStatic]
        private static HashAlgorithm InternalMD5Provider;

        /// <summary>
        /// 获得 MD5Cng 实例。
        /// </summary>
        public static HashAlgorithm MD5Provider
        {
            get
            {
                var Result = InternalMD5Provider;

                if (Result == null)
                {
                    Result = new MD5Cng();

                    InternalMD5Provider = Result;
                }

                return Result;
            }
        }

        /// <summary>
        /// 取得字符串 UTF-8 编码的 MD5 值。
        /// </summary>
        /// <param name="Text">字符串</param>
        /// <returns>返回 16 字节 MD5 值。</returns>
        public static Guid MD5(string Text)
        {
            var Bytes = MD5Provider.ComputeHash(Encoding.UTF8.GetBytes(Text));

            byte Swap;

            Swap = Bytes[0];
            Bytes[0] = Bytes[3];
            Bytes[3] = Swap;

            Swap = Bytes[1];
            Bytes[1] = Bytes[2];
            Bytes[2] = Swap;

            Swap = Bytes[4];
            Bytes[4] = Bytes[5];
            Bytes[5] = Swap;

            Swap = Bytes[6];
            Bytes[6] = Bytes[7];
            Bytes[7] = Swap;

            return new Guid(Bytes);
        }

        /// <summary>
        /// 颠倒字符串内容。
        /// </summary>
        /// <param name="Text">字符串</param>
        /// <returns>返回一个新的字符串</returns>
        public unsafe static string Reverse(this string Text)
        {
            string Result = new string('\0', Text.Length);

            fixed (char* LpResult = Result)
            {
                for (int i = 0, j = Text.Length - 1; j >= 0; i++, --j)
                {
                    LpResult[i] = Text[j];
                }
            }

            return Result;
        }

        /// <summary>
        /// 将字符串中的格式项 ({Index})替换为数组中相应的字符串。可以用 '\' 字符让字符串直接复制下一个字符。
        /// </summary> 
        /// <param name="Text">字符串</param>
        /// <param name="Args">数组</param>
        /// <returns>返回一个新的字符串。</returns>
        public unsafe static string Format(string Text, params string[] Args)
        {
            if (Text == null)
            {
                return null;
            }

            fixed (char* LpText = Text)
            {
                int ResultLength;
                int Begin = 0;
                int End = ResultLength = Text.Length;

                GetLengthLoop:
                int Index = IndexOf(LpText, '\\', '{', Begin, End);

                if (Index == -1)
                {
                    if (Begin == 0)
                    {
                        return Text;
                    }

                    goto Format;
                }

                if (LpText[Index] == '\\')
                {
                    --ResultLength;

                    Begin = Index + 2;
                }
                else
                {
                    ++Index;

                    Begin = Index;

                    if (Index < End && LpText[Index] >= '0' && LpText[Index] <= '9')
                    {
                        int Number = LpText[Index] - '0';

                        for (++Index; Index < End; ++Index)
                        {
                            if (LpText[Index] >= '0' && LpText[Index] <= '9')
                            {
                                Number = Number * 10 + LpText[Index] - '0';
                            }
                            else if (LpText[Index] == '}')
                            {
                                if (Args[Number] != null)
                                {
                                    ResultLength += Args[Number].Length;

                                    ResultLength -= Index - Begin + 2;
                                }

                                Begin = Index + 1;

                                break;
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                }

                goto GetLengthLoop;

                Format:
                Begin = 0;

                var Result = new string('\0', ResultLength);

                int ResultIndex = 0;

                fixed (char* LpResult = Result)
                {
                    FormatLoop:
                    Index = IndexOf(LpText, '\\', '{', Begin, End);

                    if (Index == -1)
                    {
                        Index = End;
                    }

                    for (; Begin < Index; ++Begin)
                    {
                        LpResult[ResultIndex] = LpText[Begin];

                        ++ResultIndex;
                    }

                    if (ResultIndex == ResultLength)
                    {
                        return Result;
                    }

                    if (LpText[Index] == '\\')
                    {
                        ++Index;

                        if (Index == End)
                        {
                            return Result;
                        }

                        LpResult[ResultIndex] = LpText[Index];

                        ++ResultIndex;

                        Begin = Index + 1;
                    }
                    else
                    {
                        ++Index;

                        if (Index < End && LpText[Index] >= '0' && LpText[Index] <= '9')
                        {
                            int Number = LpText[Index] - '0';

                            for (++Index; Index < End; ++Index)
                            {
                                if (LpText[Index] >= '0' && LpText[Index] <= '9')
                                {
                                    Number = Number * 10 + LpText[Index] - '0';
                                }
                                else if (LpText[Index] == '}')
                                {
                                    if (Args[Number] != null)
                                    {
                                        int ArgLength = Args[Number].Length;

                                        fixed (char* LpArg = Args[Number])
                                        {
                                            for (int ArgIndex = 0; ArgIndex < ArgLength; ArgIndex++)
                                            {
                                                LpResult[ResultIndex] = LpArg[ArgIndex];

                                                ++ResultIndex;
                                            }
                                        }
                                    }

                                    Begin = Index + 1;

                                    goto FormatLoop;
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }

                        for (; Begin < Index; ++Begin)
                        {
                            LpResult[ResultIndex] = LpText[Begin];

                            ++ResultIndex;
                        }
                    }

                    goto FormatLoop;
                }
            }
        }

        /// <summary>
        /// 比较两个字符串是否相同。如果字符串 1 比字符串 2 长，但两个字符串前面的内容相同也返回 true。如果字符串 1 比字符串 2 短则直接返回 false。
        /// </summary>
        /// <param name="Text">字符串 1</param>
        /// <param name="Begin">字符串 1 的开始索引</param>
        /// <param name="End">字符串 1 的结束索引，比较的位置不包含此值。</param>
        /// <param name="Chars">字符串 2 </param>
        /// <returns>返回一个 bool 值。</returns>
        public unsafe static bool Equals(char* Text, int Begin, int End, string Chars)
        {
            if (End - Begin < Chars.Length)
            {
                return false;
            }

            for (int i = 0; i < Chars.Length && Begin < End; ++i, ++Begin)
            {
                if (Text[Begin] != Chars[i])
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// 比较两个字符串是否相同，忽略英文字符大小写。如果字符串 1 比字符串 2 长，但两个字符串前面的内容相同也返回 true。如果字符串 1 比字符串 2 短则直接返回 false。
        /// </summary>
        /// <param name="Text">字符串 1</param>
        /// <param name="Begin">字符串 1 的开始索引</param>
        /// <param name="End">字符串 1 的结束索引，比较的位置不包含此值。</param>
        /// <param name="Chars">字符串 2 </param>
        /// <returns>返回一个 bool 值。</returns>
        public unsafe static bool IgnoreCaseEquals(char* Text, int Begin, int End, string Chars)
        {
            if (End - Begin < Chars.Length)
            {
                return false;
            }

            for (int i = 0; i < Chars.Length && Begin < End; ++i, ++Begin)
            {
                if (char.ToUpper(Text[Begin]) != Chars[i])
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// 裁剪字符串
        /// </summary>
        /// <param name="Text">字符串</param>
        /// <param name="Begin">开始索引</param>
        /// <param name="End">结束索引，裁剪的位置不包含此值。</param>
        /// <returns>返回一个新的字符串。</returns>
        public unsafe static string Substring(char* Text, int Begin, int End)
        {
            if (Begin > End)
            {
                throw new ArgumentException("字符串开始索引不能大于结束索引。");
            }

            if (Begin == End)
            {
                return "";
            }

            return new string(Text, Begin, End - Begin);
        }

        /// <summary>
        /// 去除字符串两端的的空白字符
        /// </summary>
        /// <param name="Text">字符串</param>
        /// <param name="Begin">开始索引</param>
        /// <param name="End">结束索引，裁剪的位置不包含此值。</param>
        /// <returns>返回一个新的字符串。</returns>
        public unsafe static string Trim(char* Text, int Begin, int End)
        {
            while (Begin < End && char.IsWhiteSpace(Text[Begin]))
            {
                ++Begin;
            }

            do
            {
                --End;
            } while (End >= Begin && char.IsWhiteSpace(Text[End]));

            return Substring(Text, Begin, End + 1);
        }

        /// <summary>
        /// 在字符串中找到指定字符的索引，没找到则返回 -1
        /// </summary>
        /// <param name="Text">字符串</param>
        /// <param name="Char">字符</param>
        /// <param name="Begin">开始查找的位置。</param>
        /// <param name="End">结束查找的位置，不包含此值。</param>
        /// <returns>返回一个 int 值。</returns>
        public unsafe static int IndexOf(char* Text, char Char, int Begin, int End)
        {
            while (Begin < End)
            {
                if (Text[Begin] == Char)
                {
                    return Begin;
                }

                ++Begin;
            }

            return -1;
        }

        /// <summary>
        /// 在字符串中找到第一个字符 1 或字符 2 的索引，两个字符都没找到则返回 -1
        /// </summary>
        /// <param name="Text">字符串</param>
        /// <param name="Char1">字符 1</param>
        /// <param name="Char2">字符 2</param>
        /// <param name="Begin">开始查找的位置。</param>
        /// <param name="End">结束查找的位置，不包含此值。</param>
        /// <returns>返回一个 int 值。</returns>
        public unsafe static int IndexOf(char* Text, char Char1, char Char2, int Begin, int End)
        {
            while (Begin < End)
            {
                if (Text[Begin] == Char1 || Text[Begin] == Char2)
                {
                    return Begin;
                }

                ++Begin;
            }

            return -1;
        }

        /// <summary>
        /// 在字符串 1 中找到字符串 2 的索引，没找到则返回 -1
        /// </summary>
        /// <param name="Text">字符串 1</param>
        /// <param name="Chars">字符串 2</param>
        /// <param name="Begin">开始查找的位置</param>
        /// <param name="End">结束查找的位置，不包含此值。</param>
        /// <returns>返回一个 int 值。</returns>
        public unsafe static int IndexOf(char* Text, string Chars, int Begin, int End)
        {
            if (Chars.Length == 0)
            {
                return -1;
            }

            Loop:
            while (Begin < End)
            {
                if (Text[Begin] == Chars[0])
                {
                    for (int i = 1, j = Begin + 1; i < Chars.Length && j < End; ++i, ++j)
                    {
                        if (Chars[i] != Text[j])
                        {
                            goto Loop;
                        }
                    }

                    return Begin;
                }

                ++Begin;
            }

            return -1;
        }

        /// <summary>
        /// 在字符串中找到字符集合中第一个出现的索引，没找到则返回 -1
        /// </summary>
        /// <param name="Text">字符串</param>
        /// <param name="Chars">字符集合</param>
        /// <param name="Begin">开始查找的位置。</param>
        /// <param name="End">结束查找的位置，不包含此值。</param>
        /// <returns>返回一个 int 值。</returns>
        public unsafe static int IndexOf(char* Text, char[] Chars, int Begin, int End)
        {
            while (Begin < End)
            {
                for (int i = 0; i < Chars.Length; ++i)
                {
                    if (Text[Begin] == Chars[i])
                    {
                        return Begin;
                    }
                }

                ++Begin;
            }

            return -1;
        }

        /// <summary>
        /// 在字符串中找到第一个未被转义的指定字符的索引，没找到则返回 -1
        /// </summary>
        /// <param name="Text">字符串</param>
        /// <param name="Char">字符</param>
        /// <param name="Begin">开始查找的位置。</param>
        /// <param name="End">结束查找的位置，不包含此值。</param>
        /// <returns>返回一个 int 值。</returns>
        public unsafe static int NoEscapeIndexOf(char* Text, char Char, int Begin, int End)
        {
            while (Begin < End)
            {
                if (Text[Begin] == Char)
                {
                    return Begin;
                }
                else if (Text[Begin] == '\\')
                {
                    Begin += 2;
                }
                else
                {
                    ++Begin;
                }
            }

            return -1;
        }

        /// <summary>
        /// 获得字符在字符串中出现的次数。
        /// </summary>
        /// <param name="LpText">字符串</param>
        /// <param name="Begin">字符串开始位置</param>
        /// <param name="End">字符串结束位置，不包含此位置</param>
        /// <param name="Char">字符</param>
        /// <returns>返回一个 int 值</returns>
        public unsafe static int CountOf(char* LpText, int Begin, int End, char Char)
        {
            int Result = 0;

            while (Begin < End)
            {
                if (LpText[Begin] == Char)
                {
                    ++Result;
                }

                ++Begin;
            }

            return Result;
        }

        /// <summary>
        /// 计算字符串的哈希值。
        /// </summary>
        /// <param name="Text">字符串</param>
        /// <returns>返回一个 Hash 值。</returns>
        public static uint ComputeStringHash(string Text)
        {
            uint Result = 0x811c9dc5;

            for (int i = 0; i < Text.Length; i++)
            {
                Result = (Text[i] ^ Result) * 0x1000193;
            }

            return Result;
        }
    }
}